home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / infoserv / gopher / Unix / GopherTools / linkmerge.pl.1.Z / linkmerge.pl.1
Encoding:
Text File  |  1994-08-10  |  15.3 KB  |  450 lines

  1. spssig.spss.com!news.oc.com!eff!sol.ctr.columbia.edu!usc!cs.utexas.edu!newsfeed.rice.edu!rice!riddle Fri Mar 26 09:04:35 CST 1993
  2. Article: 1608 of comp.infosystems.gopher
  3. Xref: feenix.metronet.com comp.infosystems.gopher:1608
  4. Newsgroups: comp.infosystems.gopher
  5. Path: feenix.metronet.com!spssig.spss.com!news.oc.com!eff!sol.ctr.columbia.edu!usc!cs.utexas.edu!newsfeed.rice.edu!rice!riddle
  6. From: riddle@ruf.rice.edu (Prentiss Riddle)
  7. #Subject: linkmerge: a tool to merge remote Gopher directories
  8. Message-ID: <C4Guvw.4yx@rice.edu>
  9. Sender: news@rice.edu (News)
  10. Organization: Ministry of Information, William's Marsh
  11. Date: Thu, 25 Mar 1993 22:38:19 GMT
  12. Lines: 434
  13.  
  14. Problem: I want to offer a "subject tree" of Internet resources
  15. categorized by subject area but I don't have time to develop my own.
  16. There are a number of useful efforts to categorize Gopher resources by
  17. subject area, but none of them has yet emerged as a comprehensive
  18. standard.
  19.  
  20. Solution: The perl script below.  By merging carefully selected
  21. subdirectories of other sites' subject area trees, I was able to come
  22. up with a pretty fair union of several of them.  The result is far from
  23. perfect, but it will do until something better comes along.  This
  24. approach also allows me to put my own local resources into the same
  25. tree.  To see this in action, take a look at:
  26.  
  27. Name=Information by Subject Area
  28. Type=1
  29. Port=70
  30. Path=1/Subject
  31. Host=riceinfo.rice.edu
  32.  
  33. I'm interested in what other people think of this idea.
  34.  
  35. -- Prentiss Riddle ("aprendiz de todo, maestro de nada") riddle@rice.edu
  36. -- Unix Systems Programmer, Office of Networking and Computing Systems
  37. -- Rice University, POB 1892, Houston, TX 77251 / Mudd 208 / 713-285-5327
  38. -- Opinions expressed are not necessarily those of my employer.
  39. ------------------------------< cut here >------------------------------
  40. #!/usr/local/bin/perl
  41. #
  42. # linkmerge 0.1 -- merge a group of links to gopher resources
  43. #
  44. # usage: linkmerge < links-to-dirs-to-be-merged > .merged-links
  45. #
  46. # Linkmerge is intended as a way to make use of efforts elsewhere in
  47. # Gopherspace to gather collections of Internet resources organized
  48. # by subject.  Linkmerge examines a specified set of Gopher directories
  49. # and produces a merged list of links to their contents.  It makes an
  50. # attempt to eliminate duplicate links and to resolve WAIS and go4gw
  51. # resources to use local servers.  Linkmerge also allows for a "stop
  52. # list" of resources which it should suppress in its output.
  53. #
  54. #
  55. # INPUT FORMAT:
  56. # The input consists of gopher links to the directories to be merged,
  57. # as well as individual resources to be suppressed, in the following
  58. # format (note that the tabs are essential):
  59. #
  60. #    merge <tab> path <tab> host <tab> port
  61. #    stop  <tab> path <tab> host <tab> port
  62. #
  63. # OUTPUT FORMAT:
  64. # The output is in the format of a gopherd .links file with comments to
  65. # help in debugging, e.g.:
  66. #
  67. #    # Merging 1/.dir/ams.taes.ag.resource tamuts.tamu.edu 70
  68. #    # Merging 1/catalog/Agriculture flubber.ciesin.org 70
  69. #    # Merging 1/Selected/Agriculture hunter.unr.edu 70
  70. #    
  71. #    Name=CYFER-net USDA ES Gopher Server.
  72. #    #     from tamuts.tamu.edu
  73. #    Path=
  74. #    Host=cyfer.esusda.gov
  75. #    Port=70
  76. #    Type=1
  77. #    #Also CYFER-net USDA ES Gopher Server.
  78. #    #     from flubber.ciesin.org
  79. #    
  80. #    Name=Agricola
  81. #    #     from tamuts.tamu.edu
  82. #    Path=
  83. #    Host=isn.iastate.edu
  84. #    Port=0
  85. #    Type=8
  86. #    #Also Agricola
  87. #    #     from flubber.ciesin.org
  88. #    
  89. #    Name=QUERRI (Database for North Central States)
  90. #    #     from hunter.unr.edu
  91. #    Path=
  92. #    Host=isn.rdns.iastate.edu
  93. #    Port=0
  94. #    Type=8
  95. #
  96. #
  97. # RESOURCE RESOLUTION:
  98. # When two or more of the input directories list the same resource, the
  99. # name in the output will be taken from the first input directory which
  100. # contained it.  For this reason, more trustworthy or better-designed
  101. # input directories should be listed first.
  102. #
  103. # If the following configuration variables are defined below, this program
  104. # will try to resolve links to WAIS indexes to a local copy:
  105. #    $waisdir $waishost $waispath $waisport
  106. #
  107. # If the following configuration variables are defined below, this program
  108. # will resolve remote go4gw links to use a local go4gw server:
  109. #    $go4gwhost $go4gwport @go4gwserv
  110. #
  111. # Note that "stop" operations take place *after* the above resolutions.
  112. #
  113. #
  114. # EXAMPLE:
  115. # Here is a simple shell script using linkmerge which could be called from
  116. # crontab.
  117. #
  118. #    #!/bin/csh -f
  119. #    #
  120. #    # Script to use linkmerge to merge several collections of
  121. #    # agriculture resources.
  122. #    #
  123. #    set MERGE="/foo/cwis/bin/linkmerge"
  124. #    set SUBJDIR="/foo/cwis/gopher/world/BySubject"
  125. #    
  126. #    if ( -f $SUBJDIR/Agriculture/.mergelinks ) then
  127. #        /bin/mv -f $SUBJDIR/Agriculture/.mergelinks \
  128. #            $SUBJDIR/.oldlinks/Agriculture
  129. #    endif
  130. #    $MERGE > $SUBJDIR/Agriculture/.mergelinks <<'EOF'
  131. #    merge    1/.dir/ams.taes.ag.resource    tamuts.tamu.edu    70
  132. #    merge    1/catalog/Agriculture    flubber.ciesin.org    70
  133. #    stop    1/.data/owl-eradication    tamuts.tamu.edu    70
  134. #    'EOF'
  135. #
  136. #----------------------------------------------------------------------------
  137. # History:
  138. # 03/18/93 PASR  Original version by Prentiss Riddle (riddle@rice.edu), but
  139. #                based on gopherclone by Bob Alberti
  140. #                (alberti@boombox.micro.umn.edu) and friends:
  141. #                   original NNTP client suggested by eci386!clewis
  142. #                   socket code by cmf@obie.cis.pitt.edu (Carl M. Fongheiser)
  143. #                   adaptation for gopher by emv@msen.com (Edward Vielmetti)
  144. #                   mods to indexer by Bob Alberti
  145. i# 03/25/93 PASR  Declared this version 0.1 and posted it to the net.
  146. #----------------------------------------------------------------------------
  147. #
  148. # CONFIGURATION -- set these variables to suit your site
  149.  
  150. $debug = 0;        # Turn off for fewer comments in output
  151.  
  152. # Local Gopher/WAIS configuration information.  Define these variables
  153. # if a Gopher server on the local machine contains an extensive directory
  154. # of WAIS sources and you'd rather make WAIS queries via your local Gopher
  155. # server than a remote Gopher server.  If you do not wish to use this
  156. # feature, leave these variables undefined.
  157. #
  158. # Note that the program will *look* for a matching WAIS ".src" file on
  159. # the local machine and only transform the link to use it if a match is
  160. # found.  It will look in two places: (1) the directory $dir and (2) a
  161. # subdirectory  of $dir consisting of the first letter of the name of
  162. # the WAIS source (e.g., "$dir/Foobar.src" and "$dir/f/Foobar.src").
  163. #
  164. # Variables:
  165. #   $waishost   hostname of your Gopher server (should be this machine)
  166. #   $waisport   port number of your Gopher server
  167. #   $waisdir    full Unix directory in which to look for WAIS sources
  168. #   $waispath   Gopher path (i.e., relative to the top of your Gopher tree)
  169. #                  of your WAIS sources
  170. # Example:
  171. #   $waishost = "gopher.foobar.edu";
  172. #   $waisport = 70;
  173. #   $waisdir = "/usr/gopher/Other/WAIS";
  174. #   $waispath = "/Other/WAIS";
  175.  
  176. # Host and port of your local go4gw gateway and the services which it
  177. # provides.  Define these if you run a go4gw gateway and you wish for
  178. # links to be translated to use it instead of remote go4gw gateways.
  179. # (Note: this could backfire if there are non-go4gw paths which look
  180. # like go4gw ones.)
  181. #
  182. # If you do not wish to use this feature (or if you don't know what go4gw
  183. # does :-) ), leave these variables undefined.
  184. #
  185. # Variables:
  186. #   $go4gwhost   hostname of host where your go4gw gateway runs
  187. #   $go4gwport   port number of your go4gw gateway
  188. #   @go4gwserv   list of go4gw services you wish to have translated
  189. #
  190. # Example:
  191. #   $go4gwhost = "gopher.foobar.edu";
  192. #   $go4gwport = 9999;
  193. #   @go4gwserv = ("areacode", "ftp", "geo", "nntp");
  194.  
  195. # END OF CONFIGURATION SECTION 
  196. #----------------------------------------------------------------------------
  197. #
  198. #Data structures:
  199. #
  200. # @merge    A list of links to Gopher directories to be merged.
  201. #        Its values consist of tab-separated Gopher links in the
  202. #        form "path<tab>host<tab>port".
  203. #
  204. # %stop        A table of links to resources to be suppressed.  Its
  205. #               indexes consist of tab-separated Gopher links in the
  206. #               form "path<tab>host<tab>port".  It returns "1"
  207. #        for any resource which appeared in a "stop" line on
  208. #        input.  Gopher links used to index it should be forced
  209. #               to lowercase prior to insertion or lookup in order to
  210. #               eliminate mismatches caused by case distinction.
  211. #
  212. # %links    A table of all of the Gopher links we've seen so far.  Its
  213. #        indexes consist of tab-separated Gopher links in the
  214. #        form "path<tab>host<tab>port<tab>type".  The values it
  215. #        returns are the numeric indices of the other tables
  216. #        here.  Gopher links used to index it should be forced
  217. #        to lowercase prior to insertion or lookup in order to
  218. #        eliminate false duplicates caused by case distinction.
  219. #
  220. # @paths    The path of each link, indexed by a value returned by
  221. #        $links[].
  222. #
  223. # @hosts    The host of each link, indexed by a value returned by
  224. #        $links[].
  225. #
  226. # @ports    The port of each link, indexed by a value returned by
  227. #        $links[].
  228. #
  229. # @types    The type of each link, indexed by a value returned by
  230. #        $links[].
  231. #
  232. # @names    The names associated with each link, indexed by a value
  233. #        returned by $links[].  Each value returned by $names[]
  234. #        can have multiple tab-separated names, but only the
  235. #        first is used to generate a "live" link in the output;
  236. #        the others are available for debugging purposes.
  237. #
  238. # @viahosts    The hosts where each link was found, indexed by a value
  239. #        returned by $links[].  Each value returned by $viahosts[]
  240. #        can have multiple tab-separated hostnames.  This
  241. #        information is kept for debugging purposes.
  242. #
  243. # $nlinks    Number of entries (starting with 1) in the lists indexed
  244. #        by %links.
  245. #----------------------------------------------------------------------------
  246.  
  247. # Here's how to make your own socket.ph:
  248. #    cp /usr/include/sys/socket.h socket.h
  249. require 'socket.ph';  # h2ph socket
  250.  
  251. # Read the input and save it into @merge and %stop.
  252. while (<STDIN>) {
  253.     chop;
  254.     $op = "";
  255.     ($op, $path, $host, $port) =
  256.         /^(\S*) *\t([^\t]*)\t(\S+)\t(\d+)$/;
  257.     if ($op eq "stop") {
  258.         # Add it to the stop list.
  259.         $link = "$path\t$host\t$port";
  260.         $link =~ tr/A-Z/a-z/;
  261.         $stop{$link} = 1;
  262.         print("# Stop  $link\n");
  263.         next;
  264.     }
  265.     unless ($op eq "merge") {
  266.         print("# UNRECOGNIZED INPUT: $_\n");
  267.         next;
  268.     }
  269.     push(@merge, "$path\t$host\t$port");
  270.     print("# Merge $path $host $port\n");
  271. }
  272. print("#\n");
  273.  
  274. # Step through the links in @merge.
  275. $nlinks = 0;
  276. while ($mergelink = shift(@merge)) {
  277.     print("# Merging $mergelink\n");
  278.     ($path, $viahost, $port) = split(/\t/, $mergelink);
  279.  
  280.     # Make sure the path has an initial type selector (default "1/").
  281.     $path =~ s#^/#1/#;
  282.     unless ($path =~ m#^1/#) {
  283.         print("#         ^ BAD PATH -- IGNORED!\n");
  284.         next;
  285.     }
  286.     unless ($viahost && $port && $path) {
  287.         print("#         ^ INCOMPLETE PATH/HOST/PORT -- IGNORED!\n");
  288.         next;
  289.     }
  290.     
  291.     chop($hostname = `hostname`);    # get host name in variable
  292.     ($N) = &tcpconnect($viahost, $hostname);
  293.     unless ($N) {
  294.         # bad connection
  295.         print("#         ^ COULDN'T OPEN TCP CONNECTION $N!\n");
  296.         next;
  297.     }
  298.     send(N,"$path\r\n", 0)
  299.         || die "Send $d to $viahost barfed with: $!\n";
  300.     while (<N>) {
  301.         last if /^\.\r\n$/;    # loop til lone period
  302.         if (m#^(.)(.*)\t([^\t]*)\t([^\t]+)\t(\d+)\s*$#) {
  303.             # We have a link to process.
  304.             $type = $1;
  305.             $name = $2;
  306.             $path = $3;
  307.             $host = $4;
  308.             $port = $5;
  309.             $host =~ s/^\s*//;
  310.             $host =~ s/\s*$//;
  311.             $name =~ s/^\s*//;
  312.             $name =~ s/\s*$//;
  313.             &normalize();
  314.  
  315.             # Is this on our stop list?
  316.             $link = "$path\t$host\t$port";
  317.             $link =~ tr/A-Z/a-z/;
  318.             #print ("# Checking \"$link\"\n") if $debug;
  319.             if ($stop{$link}) {
  320.                 print("# STOPPED $name: $path\t$host\t$port\t$type\n") if $debug;
  321.                 next;
  322.             }
  323.  
  324.             # Re-make the link the way %links needs it. :-(
  325.             $link = "$path\t$host\t$port\t$type";
  326.             $link =~ tr/A-Z/a-z/;
  327.  
  328.             # Have we seen this one before?
  329.             if ($links{$link}) {
  330.                 # Save all names & viahosts, even for
  331.                 # links we've seen.
  332.                 $l = $links{$link};
  333.                 $names[$l] .= "$name\t";
  334.                 $viahosts[$l] .= "$viahost\t";
  335.             } else {
  336.                 # Nope -- save it.
  337.                 $links{$link} = ++$nlinks;
  338.                 $paths[$nlinks] = $path;
  339.                 $hosts[$nlinks] = $host;
  340.                 $ports[$nlinks] = $port;
  341.                 $types[$nlinks] = $type;
  342.                 $names[$nlinks] = "$name\t";
  343.                 $viahosts[$nlinks] = "$viahost\t";
  344.             }
  345.             print("#         $name: $path\t$host\t$port\t$type\n") if $debug;
  346.         } else {
  347.             print("#         ^ BAD MATCH: $_\n");
  348.         }
  349.     }
  350.     close(N);
  351. }
  352. undef(%links);        # don't need this any more...
  353.  
  354. # Now unroll our data structures and generate a report in the form of
  355. # a Gopher ".links" file.
  356. for ($l = 1; $l <= $nlinks; $l++ ) {
  357.     @thesenames = split(/\t/, $names[$l]);
  358.     @theseviahosts = split(/\t/, $viahosts[$l]);
  359.     print("\nName=$thesenames[0]\n#     from $theseviahosts[0]\n");
  360.     print("Path=$paths[$l]\n");
  361.     print("Host=$hosts[$l]\n");
  362.     print("Port=$ports[$l]\n");
  363.     print("Type=$types[$l]\n");
  364.     for ($i = 1; $i <= $#thesenames; $i++) {
  365.         print("#Also $thesenames[$i]\n");
  366.         print("#     from $theseviahosts[$i]\n");
  367.     }
  368. }
  369.  
  370. #----------------------------------------------------------------------------
  371. # Normalize a gopher link prior to saving it in %linktab.
  372. # Our goal here is largely to resolve duplicates, but we also translate
  373. # some links to remote servers to use local ones if possible.
  374. #
  375. # Global variables used:
  376. #    $host $name $path $port $type
  377. #    $go4gwhost $go4gwport @go4gwserv
  378. #    $waisdir $waishost $waispath $waisport
  379.  
  380. sub normalize {
  381.     local($firstchar, $service, $waissrc);
  382.  
  383.     # Try to resolve WAIS sources to something available locally.
  384.     # Look in both $waisdir and subdirectories based on its first char.
  385.     if ($type eq "7" && $path =~ m#waissrc:.*/([^/*]+.src)#) {
  386.         # WAIS source -- is this available locally?
  387.         $waissrc = $1;
  388.         $firstchar = substr($waissrc, 0, 1);
  389.         $firstchar =~ tr/A-Z/a-z/;
  390.         if (-d $waisdir && -f "$waisdir/$waissrc") {
  391.             $host = $waishost;
  392.             $port = $waisport;
  393.             $path = "waissrc:$waispath/$waissrc";
  394.         } elsif (-d "$waisdir/$firstchar" &&
  395.                 -f "$waisdir/$firstchar/$waissrc") {
  396.             $host = $waishost;
  397.             $port = $waisport;
  398.             $path = "waissrc:$waispath/$firstchar/$waissrc";
  399.         }
  400.     }
  401.  
  402.     # Try to resolve remote go4gw gateways to the local one.
  403.     # (Note: this could backfire if there are non-go4gw paths which
  404.     # look like go4gw ones.)
  405.     if ($go4gwhost) {
  406.         ($service) = $path =~ /^(\w*)/;
  407.         if ($service && grep(/$service/, @go4gwserv)) {
  408.             $host = $go4gwhost;
  409.             $port = $go4gwport;
  410.         }
  411.     }
  412.     if ($path =~ /^nntp / && $nntphost && $nntpport) {
  413.         $host = $nntphost;
  414.         $port = $nntpport;
  415.     }
  416.  
  417.     # TO DO: substitute a local g2ftp gateway.
  418. }
  419.  
  420. #----------------------------------------------------------------------------
  421. sub tcpconnect {                    #Get TCP info in place
  422.    local($host, $hostname) = @_;
  423.    $sockaddr = 'S n a4 x8';
  424.  
  425.  
  426.    ($name,$aliases,$proto) = getprotobyname('tcp');
  427.    ($name,$aliases,$port) = getservbyname($port, 'tcp')
  428.         unless $port =~ /^\d+$/;
  429.    ($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname);
  430.    ($name,$aliases,$type,$len,$thataddr) = gethostbyname($host);
  431.  
  432.    $this = pack($sockaddr, &AF_INET, 0, $thisaddr);
  433.    $that = pack($sockaddr, &AF_INET, $port, $thataddr);
  434.  
  435.    sleep(2);
  436.  
  437.    #socket(N, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
  438.    #bind(N, $this)                            || die "bind: $!";
  439.    #connect(N, $that)                         || die "connect: $!";
  440.    socket(N, &PF_INET, &SOCK_STREAM, $proto) || return 0;
  441.    bind(N, $this)                            || return 0;
  442.    connect(N, $that)                         || return 0;
  443.  
  444.    return(N);
  445. }
  446. #----------------------------------------------------------------------------
  447. # end of linkmerge
  448.  
  449.  
  450.